package com.sahyadri.web.google.calendar;

import com.google.gdata.client.Query;
import com.google.gdata.client.calendar.CalendarQuery;
import com.google.gdata.client.calendar.CalendarService;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.Person;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.TextContent;
import com.google.gdata.data.calendar.CalendarEntry;
import com.google.gdata.data.calendar.CalendarFeed;
import com.google.gdata.data.calendar.CalendarEventEntry;
import com.google.gdata.data.calendar.CalendarEventFeed;
import com.google.gdata.data.calendar.EventWho;
import com.google.gdata.data.extensions.Recurrence;
import com.google.gdata.data.extensions.Reminder;
import com.google.gdata.data.extensions.When;
import com.google.gdata.data.extensions.Who;
import com.google.gdata.data.extensions.Who.AttendeeStatus;
 
import java.io.PrintStream;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* An application that serves as a sample to show how the CalendarService
* can be used to create/read/update/delete data on Google Calendar.
*
* 
*/
  public class CalendarClient {

  private static final String CALENDAR_FEEDS_URL = "http://www.google.com/calendar/feeds";

 private CalendarService calendarService;
 private URL privateFeedUrl;

 public CalendarClient(String username, String password)
	        throws Exception {
    calendarService = new CalendarService("sahyadri-calendar");
    calendarService.setUserCredentials(username, password);
    privateFeedUrl = new URL(CALENDAR_FEEDS_URL + "/default/private/full");
  }

  /**
   * Driver for the sample.
   *
   * @param out outputStream to which to write status and messages
   */
	    public void run(PrintStream out) throws Exception {
    // Retrieve entire feed of events
    retrieveFeed(out);

    // Add an event
    CalendarEventEntry event = addEvent(out);

    // Send a full-text search query
    String attendeeEmail = event.getParticipants().get(0).getEmail();
    sendFullTextQuery(attendeeEmail, out);

    // Send a date-range query for all events that occur today
    Calendar todayCalendar = Calendar.getInstance();
    todayCalendar.set(Calendar.HOUR, 0);
    todayCalendar.set(Calendar.MINUTE, 0);
    todayCalendar.set(Calendar.SECOND, 0);
    todayCalendar.set(Calendar.AM_PM, Calendar.AM);
    DateTime startTime = new DateTime(new Date(todayCalendar.getTimeInMillis()));
    todayCalendar.set(Calendar.HOUR, 23);
    DateTime endTime = new DateTime(new Date(todayCalendar.getTimeInMillis()));
    sendDateRangeQuery(startTime, endTime, out);

   // Update an event
    event = updateEvent(event, out);

    // Delete an event
    out.println("Deleting entry: " + event.getSelfLink().getHref() + ".\n");
    //deleteEntry(event.getEditLink().getHref());
    event.delete();
    // Insert recurring event
    CalendarEventEntry recurringEvent = insertRecurringEvent(out);

    // Delete recurring event
    out.println("Deleting entry: " + recurringEvent.getSelfLink().getHref()
                + ".\n");
    //deleteE/ntry(recurringEvent.getEditLink().getHref());
    recurringEvent.delete();
    // List all calendars
    listAllCalendars(out);
  }

  /**
  * Retrieves the default private feed.
   *
   * @param out outputStream on which to write status info
   * @throws Exception if error in retrieving feed
   */
  private void retrieveFeed(PrintStream out)
	        throws Exception {
    CalendarEventFeed myFeed =
     calendarService.getFeed(privateFeedUrl, CalendarEventFeed.class);
    out.println("Retrieved feed with title: " + myFeed.getTitle().getPlainText() +
                "\nNumber of events in feed: " + myFeed.getEntries().size() +
                "\n");
  }

  /**
  * Adds an event that starts at 10AM today to the calendar.
   *
   * @param out outputStream on which to write status info
   * @return the added event
   * @throws Exception if error in adding event
   */
  private CalendarEventEntry addEvent(PrintStream out)
	        throws Exception {
    // Get the start and end time for today at 10AM - 11AM
   Calendar todayCalendar = Calendar.getInstance();
    todayCalendar.set(Calendar.HOUR, 10);
    todayCalendar.set(Calendar.MINUTE, 0);
    todayCalendar.set(Calendar.SECOND, 0);
    todayCalendar.set(Calendar.AM_PM, Calendar.AM);
    DateTime startTime = new DateTime(new Date(todayCalendar.getTimeInMillis()));
    todayCalendar.set(Calendar.HOUR, 11);
    DateTime endTime = new DateTime(new Date(todayCalendar.getTimeInMillis()));

    // Create attendee list
    Map<String, String> attendees = new HashMap<String,String>();
    attendees.put("mohan.giramkar@gmail.com", AttendeeStatus.EVENT_INVITED);

    // Add event
    CalendarEventEntry event =
      insertEntry("Lunch with Mohan", "Lunch to discuss plans", null, null,
                  startTime, endTime, null, attendees, /*reminderMinutes*/ 5);

   out.println("Added event with title: \"" + event.getTitle().getPlainText()
               + "\" and ID: \"" + event.getId() + "\"\n");
    return event;
  }

  /**
   * Adds a recurring event.
   *
   * @param out outputStream on which to write status info
   * @return the added event
   * @throws Exception if error in adding event
   */
  private CalendarEventEntry insertRecurringEvent(PrintStream out)
	        throws Exception {
    // Metadata for an all day recurring event.  First day of meeting is
    // 2006/05/02 and repeats weekyly on Thursdays.
    String recurData =
      "DTSTART;VALUE=DATE:20060502\n" +
      "DTEND;VALUE=DATE:20060503\n" +
      "RRULE:FREQ=WEEKLY;BYDAY=Tu\n" +
      "BEGIN:VTIMEZONE\n" +
      "TZID:PST\n" +
      "BEGIN:STANDARD\n" +
      "TZOFFSETFROM:-0700\n" +
      "TZOFFSETTO:-0800\n" +
      "DTSTART:19700101T000000\n" +
      "RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10\n" +
      "END:STANDARD\n" +
     "BEGIN:DAYLIGHT\n" +
      "TZOFFSETFROM:-0800\n" +
      "TZOFFSETTO:-0700\n" +
      "DTSTART:19700101T000000\n" +
      "RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4\n" +
      "END:DAYLIGHT\n" +
      "END:VTIMEZONE\n";

    // Add event
    CalendarEventEntry event = insertEntry("Meeting", "Recurring meeting",
                                           null, null, null, null, recurData,
                                           null, /*reminderMinutes*/ 5);
    out.println("Added event with title: \"" + event.getTitle().getPlainText()
                + "\" and ID: \"" + event.getId() + "\"\n");
    return event;
  }

  /**
   * Updates the provided event by changing the details of the event.
   *
   * @param entry the entry to update
   * @param out outputStream on which to write status info
   * @return the updated entry
   * @throws Exception if error on update
   */
  private CalendarEventEntry updateEvent(CalendarEventEntry entry,
                                         PrintStream out)
	        throws Exception {
    entry.setContent(new PlainTextConstruct("Also invite Elizabeth"));
    URL newEntryUrl = new URL(entry.getEditLink().getHref());

    // Also change all the attendees to 'accepted' status
    // Create attendee list
    List<EventWho> attendees = entry.getParticipants();
	      for (int i = 0; i < attendees.size(); i++) {
      attendees.get(i).setAttendeeStatus(AttendeeStatus.EVENT_ACCEPTED);
    }

    CalendarEventEntry updatedEntry = calendarService.update(newEntryUrl, entry);
    out.println("Updating entry with title \"" +
                entry.getTitle().getPlainText() + "\".");
    out.println("New content: \"" + ((TextContent) updatedEntry.getContent()).
                getContent().getPlainText() + "\"");
    out.println("New attendee status:");
    attendees = updatedEntry.getParticipants();
	      for (int i = 0; i < attendees.size(); i++) {
      Who attendee = attendees.get(i);
      out.println("\t" + attendee.getEmail() + ": " +
                  attendee.getAttendeeStatus());
    }
    out.println();
    return updatedEntry;
  }

  /**
   * Perform a full text search over all the events.
   *
   * @param queryString the string to search
   * @param out outputStream on which to write status info
  * @return the feed of results
   * @throws Exception if error in querying
   */
  private CalendarEventFeed sendFullTextQuery(String queryString,
                                              PrintStream out)
	        throws Exception {
    Query myQuery = new Query(privateFeedUrl);
    myQuery.setFullTextQuery(queryString);
    CalendarEventFeed resultFeed =
      calendarService.query(myQuery, CalendarEventFeed.class);

    out.println("Full text search for query: \"" + queryString +
                "\" and retrieved " + resultFeed.getEntries().size() +
                " events.");

	      if (resultFeed.getEntries().size() > 0) {
      out.println("Title of first event: \"" +
                  resultFeed.getEntries().get(0).getTitle().getPlainText() +
                  "\".");
    }
    out.println();
    return resultFeed;
  }

  /**
   * Insert an entry with the given parameters.
   *
   * @return the inserted entry
   * @throws Exception if error on insert
   */
 private CalendarEventEntry insertEntry(String titleText,
                                         String contentText,
                                         String authorName,
                                        String authorEmail,
                                         DateTime startTime,
                                         DateTime endTime,
                                         String recurData,
                                         Map<String, String> attendeeList,
                                         int reminderMinutes)
	        throws Exception {
    CalendarEventEntry myEntry =
      createEntryObject(titleText, contentText, authorName, authorEmail,
                        startTime, endTime, recurData, attendeeList,
                        reminderMinutes);
    // Insert entry
    CalendarEventEntry insertedEntry = calendarService.insert(privateFeedUrl,
                                                              myEntry);
    return insertedEntry;
  }

  /**
   * Creates an object that contains the provided parameters.
   *
   * @return an CalendarEventEntry object with the given parameters
   */
  private CalendarEventEntry createEntryObject(String titleText,
                                               String contentText,
                                               String authorName,
                                               String authorEmail,
                                               DateTime startTime,
                                               DateTime endTime,
                                               String recurData,
                                               Map<String, String> attendeeList,
	                                                 int reminderMinutes) {
    // Set title and content
    CalendarEventEntry myEntry = new CalendarEventEntry();
    myEntry.setTitle(new PlainTextConstruct(titleText));
      if (contentText != null) {
     myEntry.setContent(new PlainTextConstruct(contentText));
    }

    // Set author
	      if (authorName != null) {
     Person author = new Person(authorName, null, authorEmail);
      myEntry.getAuthors().add(author);
    }

    // Set recurrence
	      if (recurData != null) {
     Recurrence recur = new Recurrence();
      recur.setValue(recurData);
      myEntry.setRecurrence(recur);
    }

    // Set reminder for event
	      if (reminderMinutes > 0) {
      Reminder reminder = new Reminder();
      reminder.setMinutes(reminderMinutes);
      myEntry.addExtension(reminder);
    }

    // Set start and end time
	      if (startTime != null || endTime != null) {
      When eventTime = new When();
	        if (startTime != null) {
        eventTime.setStartTime(startTime);
      }
	        if (endTime != null) {
        eventTime.setEndTime(endTime);
      }
      myEntry.addTime(eventTime);
    }

    // Set the attendess
	      if (attendeeList != null) {
	        for (Map.Entry<String, String> entry : attendeeList.entrySet()) {
        EventWho who = new EventWho();
        who.setEmail(entry.getKey());
        who.setAttendeeStatus(entry.getValue());
        myEntry.getParticipants().add(who);
      }
    }
    return myEntry;
 }

  /**
   * Perform a date range query over the events in the calendar.
   *
   * @param min the minimum date.  (may be null)
   * @param max the maximum date.  (may be null)
   * @param out outputStream on which to write status info
   * @return the feed of results
  * @throws Exception if error in querying
   */
  private CalendarEventFeed sendDateRangeQuery(DateTime min,
                                       DateTime max,
                                       PrintStream out)
	        throws Exception {
    CalendarQuery myQuery = new CalendarQuery(privateFeedUrl);
    myQuery.setMinimumStartTime(min);
    myQuery.setMaximumStartTime(max);
    CalendarEventFeed resultFeed =
      calendarService.query(myQuery, CalendarEventFeed.class);

    out.println("Date range query (from, to): (" + min + " , " + max + ")" +
                " returned " + resultFeed.getEntries().size() + " events.");

	      if (resultFeed.getEntries().size() > 0) {
      out.println("Title of first event: \"" +
                  resultFeed.getEntries().get(1).getTitle().getPlainText() +
                  "\".");
    }
    out.println();
    return resultFeed;
  }

  /**
   * Deletes the specified entry.
   *
   * @param entryUrlString the edit URL of the entry to delete
   * @throws Exception if error in delete
   */
  private void deleteEntry(String entryUrlString)
	        throws Exception {
    URL entryUrl = new URL(entryUrlString);
    calendarService.delete(entryUrl);
  }

  /**
   * Lists all the calendars owned by the user.
   *
   * @param out outputStream on which to write status info
   * @throws Exception if error in retrieving the calendars
   */
  private void listAllCalendars(PrintStream out)
	        throws Exception {
    URL calendarsUrl = new URL(CALENDAR_FEEDS_URL + "/default");
    new CalendarFeed().declareExtensions(calendarService.getExtensionProfile());
    CalendarFeed feed = calendarService.getFeed(calendarsUrl, CalendarFeed.class);
    out.println("List of calendars for account:");
	      for(int entry_i = 0; entry_i < feed.getEntries().size(); entry_i++) {
      CalendarEntry calEntry = feed.getEntries().get(entry_i);
      out.println("\"" + calEntry.getTitle().getPlainText() + "\"\t" +
                  calEntry.getSelfLink().getHref());
    }
  }

  /**
   * Main entry point.  Parses arguments and creates and invokes the
   * CalendarClient.
   */
  public static void main(String[] arg)
	        throws Exception {
    
    String username = "sahyadrirestaurant@gmail.com";
    String password = "sahyadri28122012";
   

    CalendarClient client = new CalendarClient(username, password);
    Calendar todayCalendar = Calendar.getInstance();
    todayCalendar.set(Calendar.HOUR, 0);
    todayCalendar.set(Calendar.MINUTE, 0);
    todayCalendar.set(Calendar.SECOND, 0);
    todayCalendar.set(Calendar.AM_PM, Calendar.AM);
    DateTime startTime = new DateTime(new Date(todayCalendar.getTimeInMillis()));
    todayCalendar.set(Calendar.HOUR, 23);
    DateTime endTime = new DateTime(new Date(todayCalendar.getTimeInMillis()));
    //sendDateRangeQuery(startTime, endTime, out);

    //client.sendDateRangeQuery(startTime, endTime,System.out);
    client.sendFullTextQuery("Lunch with Mohan", System.out);
  }

  /**
   * Prints usage of this application.
   */
	    private static void usage() {
    System.out.println("Usage: java CalendarClient --username [user] " +
                       "--password [pass]");
    System.out.println(
        "\nA simple application that uses the provided Google\n" +
        "Account username and password to perform simple\n" +
        "create/read/update/delete operations against the user's\n" +
        "Google Calendar account.\n");
  }
}
